use std::iter;

use crate::{
    math::{ Matrix4f,  Vector2f, Vector3f, Vector4f},
    color::Rgba,
    pool::Handle,
    function::resource::{resource_system::AliceResource, texture::Texture},
};

use super::{pass::canvas_pass::CanvasPass,  rhi::Rhi, RenderPipelineInitInfo};

const MAX_QUAD_COUNT: usize = 10000;
const MAX_VERTEX_COUNT: usize = MAX_QUAD_COUNT * 4;
const MAX_INDEX_COUNT: usize = MAX_QUAD_COUNT * 6;
const MAX_TEXTURE_SLOT_COUNT: usize = 1;

const QUAD_VERTEX_COUNT: usize = 4;

#[derive(Debug, Clone, Copy)]
pub struct CanvasQuadVertex {
    pub pos: Vector2f,
    pub tex_coords: Vector2f,
    pub texture_index: f32,
    pub factory: f32,
    pub color: Rgba,
    // pub _padding_factory:Vector2f,
    // pub _padding_color:Vector3f,
}

unsafe impl bytemuck::Pod for CanvasQuadVertex {}
unsafe impl bytemuck::Zeroable for CanvasQuadVertex {}

const POSITIONS: [Vector4f; 4] = [
    Vector4f {
        x: -0.5,
        y: -0.5,
        z: 0.0,
        w: 1.0,
    },
    Vector4f {
        x: -0.5,
        y: 0.5,
        z: 0.0,
        w: 1.0,
    },
    Vector4f {
        x: 0.5,
        y: 0.5,
        z: 0.0,
        w: 1.0,
    },
    Vector4f {
        x: 0.5,
        y: -0.5,
        z: 0.0,
        w: 1.0,
    },
];

const TEXTURE_COORDS: [Vector2f; 4] = [
    Vector2f { x: -1.0, y: -1.0 },
    Vector2f { x: -1.0, y: 1.0 },
    Vector2f { x: 1.0, y: 1.0 },
    Vector2f { x: 1.0, y: -1.0 },
];

pub struct CanvasPipeline {
    /// 存储四边形的顶点数据
    pub quad_vertices: Vec<CanvasQuadVertex>,
    /// 存储四边形的索引数据
    pub quad_indices: Vec<u16>,
    /// 存储已经使用的四边形的数量
    /// 当四边形数量大于限定的最大四边形数量时会开启一次新的合批处理
    /// 并重置该值, 每帧开始时会被重置
    quad_index_count: usize,
    /// 纹理插槽 , 第一张为系统默认的1像素纯白纹理
    pub textures: Vec<Handle<Texture>>,
    /// 纹理插槽索引 当此索引大于 最大纹理插槽时会结束当前批处理并开启新的合批处理
    texture_slot_index: usize,

    /// 一帧合批次数
    batch_count: usize,
    // canvas 渲染 pass
    pub canvas_pass: CanvasPass,

    rhi: Rhi,
    resource: AliceResource,
    current_batch_quad: usize,
    per_frame_textures: Vec<Handle<Texture>>,
}

impl CanvasPipeline {
    pub fn new(init_info: RenderPipelineInitInfo) -> Self {
        let quad_vertices = Vec::with_capacity(MAX_VERTEX_COUNT);

        let mut quad_indices = Vec::with_capacity(MAX_INDEX_COUNT);

        let mut offset: u32 = 0;

        for _ in 0..MAX_INDEX_COUNT {
            quad_indices.push((offset + 0) as u16);
            quad_indices.push((offset + 1) as u16);
            quad_indices.push((offset + 2) as u16);
            quad_indices.push((offset + 0) as u16);
            quad_indices.push((offset + 2) as u16);
            quad_indices.push((offset + 3) as u16);

            offset += 4;
        }

        let mut textures = Vec::with_capacity(MAX_TEXTURE_SLOT_COUNT);
        textures.push(Handle::try_get_default_handle());

        Self {
            quad_vertices,
            quad_indices,
            quad_index_count: 0,
            textures,
            texture_slot_index: 1,
            batch_count: 0,
            canvas_pass: CanvasPass::new(init_info.rhi.clone()),

            rhi: init_info.rhi,
            resource: init_info.resource,
            current_batch_quad: 0,
            per_frame_textures: Vec::with_capacity(10240),
        }
    }

    /// 进入 canvas2d 的一帧开始
    /// 1. 开始准备进行合批处理
    pub fn begin_frame(&mut self) {
        // TODO 设置公共的数据 例如 相机、 相机矩阵

       

        self.batch_count = 0;
        self.per_frame_textures.clear();
        self.per_frame_textures.push(self.textures[0]);

        

        self.start_batch();
    }

    /// 设置公共的数据 例如 相机、 相机矩阵
    ///     编辑模式下 为编辑相机
    ///     运行模式下 为场景主相机
    pub fn update_scene_camera(&mut self, camera: Matrix4f) {
        // update scene
        self.canvas_pass.update_scene(self.rhi.clone(), camera);
    }

    fn start_batch(&mut self) {
        self.quad_vertices.clear();

        let default_texture = self.textures[0];
        self.textures.clear();
        self.textures.push(default_texture);
       
        self.quad_index_count = 0;
        self.texture_slot_index = 1;
        self.current_batch_quad = 0;

        // println!("quad_vertices = {}",self.quad_vertices.len());
        // println!("quad_indices = {}",self.quad_indices.len());
        // println!("quad_index_count = {}",self.quad_index_count);
        // println!("textures = {}",self.textures.len());
        // println!("texture_slot_index = {}",self.texture_slot_index);
        // println!("batch_count = {}",self.batch_count);
        // println!("current_batch_quad = {}",self.current_batch_quad);
        // println!("per_frame_textures = {}",self.per_frame_textures.len());
 
    }

    fn next_batch(&mut self) {
        
        self.end_batch();
        self.start_batch();
    }

    fn end_batch(&mut self) {
      
        self.canvas_pass.update_canvas_data(
            self.batch_count,
            self.rhi.clone(),
            &self.textures[0..self.texture_slot_index],
            &self.quad_vertices,
            &self.quad_indices[0..self.current_batch_quad * 6],
            &self.resource,
        );
        self.batch_count += 1;
    }

    pub fn end_frame(&mut self) {
        self.end_batch()
    }

    pub fn draw_quad_with_psf(
        &mut self,
        position: Vector2f,
        size: Vector2f,
        texture: Handle<Texture>,
        factory: f32,
        color: Rgba,
    ) {
        self.draw_quad_with_pst(
            Vector3f::new(position.x, position.y, 0.0),
            size,
            texture,
            factory,
            color,
        )
    }

    pub fn draw_quad_with_pst(
        &mut self,
        position: Vector3f,
        size: Vector2f,
        texture: Handle<Texture>,
        factory: f32,
        color: Rgba,
    ) {
        let transform = Matrix4f::new_translation(&position)
            * Matrix4f::new_scale(&Vector3f::new(size.x, size.y, 1.0));

        self.draw_quad_with_tfc(transform, texture, factory, color)
    }

    pub fn draw_quad_with_tc(&mut self, transform: Matrix4f, color: Rgba) {
        let texture_index = 0;
        let factory = 1.0;
        if self.quad_index_count >= MAX_INDEX_COUNT {
            self.per_frame_textures.push(self.textures[0]);
            self.next_batch()
        }

        for i in 0..QUAD_VERTEX_COUNT {
            self.quad_vertices.push(CanvasQuadVertex {
                pos: (transform * POSITIONS[i]).xy(),
                tex_coords: TEXTURE_COORDS[i],
                color,
                texture_index: texture_index as f32,
                factory,
                // _padding_factory:Vector2f::ZERO,
                // _padding_color:Vector3f::ZERO
            })
        }
        self.current_batch_quad += 1;
        self.quad_index_count += 6;
    }

    pub fn draw_quad_with_tfc(
        &mut self,
        transform: Matrix4f,
        texture: Handle<Texture>,
        factory: f32,
        color: Rgba,
    ) {
        let mut texture_index = 0;
        if self.quad_index_count >= MAX_INDEX_COUNT {
            self.per_frame_textures.push(texture);
            self.next_batch()
        }

        for i in 1..self.texture_slot_index {
            if self.textures[i] == texture {
                texture_index = i as u8;
                break;
            }
        }

        if texture_index == 0 {
            if self.texture_slot_index >= MAX_TEXTURE_SLOT_COUNT {
                self.next_batch()
            }

            texture_index = self.texture_slot_index as u8;
            self.textures.push(texture);
            self.texture_slot_index += 1;
            self.per_frame_textures.push(texture);
        }

        for i in 0..QUAD_VERTEX_COUNT {
            self.quad_vertices.push(CanvasQuadVertex {
                pos: (transform * POSITIONS[i]).xy(),
                tex_coords: TEXTURE_COORDS[i],
                color,
                texture_index: texture_index as f32,
                factory,
                // _padding_factory:Vector2f::ZERO,
                // _padding_color:Vector3f::ZERO
            })
        }
        self.current_batch_quad += 1;
        self.quad_index_count += 6;
    }

    pub fn draw(&mut self , view:&wgpu::TextureView) {
        self.end_frame();
      
        let mut encoder =
            self.rhi
                .borrow()
                .device
                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
                    label: Some("Canvas Encoder"),
                });

        // self.main_camera_pass.draw(&mut encoder, view,self.rhi.clone());
        self.canvas_pass
            .draw(&mut encoder, &view, &self.per_frame_textures);
       
                
    
        // invoke custom pass draw

        self.rhi.borrow().queue.submit(iter::once(encoder.finish()));

 
    }
}
